﻿// Shader-Based-Image-Processing (SBIP)
// http://code.google.com/p/sbip/
//
// Copyright © Frank Nagl, 2009-2011
// admin@franknagl.de
//
namespace SBIP.Helper
{
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Runtime.InteropServices;
    using Microsoft.Xna.Framework.Graphics;


    /// <summary>
    /// Helper class for different Image converts. 
    /// See function details for more information.
    /// </summary>
    public static class BitmapToTexture
    {
        /// <summary>
        /// Converts Bitmap to Texture2D.
        /// </summary>
        /// <param name="bitmap">The bitmap object, which will be converted.</param>
        /// <param name="graphicsDevice">The XNA graphics device.</param>
        /// <returns>The result texture.</returns>
        public static Texture2D ToTexture(Bitmap bitmap,
                                            GraphicsDevice graphicsDevice)
        {
            Texture2D texture;
            using (MemoryStream s = new MemoryStream())
            {
                bitmap.Save(s, ImageFormat.Png);
                s.Seek(0, SeekOrigin.Begin);
                texture = Texture2D.FromStream(graphicsDevice, s);

                s.Seek(0, SeekOrigin.Begin);
            }
            return texture;
        }

        /// <summary>
        /// Converts Bitmap to Texture2D.
        /// </summary>
        /// <param name="bitmap">The bitmap object, which will be converted.
        /// </param>
        /// <param name="graphicsDevice">The XNA graphics device.</param>
        /// <param name="texture">The result texture.</param>
        public static void ToTexture(Bitmap bitmap,
                                            GraphicsDevice graphicsDevice,
                                            out Texture2D texture)
        {
            using (MemoryStream s = new MemoryStream())
            {
                bitmap.Save(s, ImageFormat.Png);
                s.Seek(0, SeekOrigin.Begin);
                texture = Texture2D.FromStream(graphicsDevice, s);

                s.Seek(0, SeekOrigin.Begin);
            }
        }

        /// <summary>
        /// Converts Texture2D to 24 bit Bitmap.
        /// </summary>
        /// <param name="texture">The texture Object, which will be converted.
        /// </param>
        /// <returns>Result Bitmap.</returns>
        public static Bitmap TextureTo8Bit(Texture2D texture)
        {
            byte[] texData = new byte[4 * texture.Width * texture.Height];
            texture.GetData(texData);
            // offset in rgb or 8bit images //wrong: int offset = 4 - (3 * texture.Width) % 4;
            int offset = (3 * texture.Width) % 4;
            if (offset != 0)
                offset = 4 - offset;
            byte[] texData8Bit = new byte[(texture.Width + offset) * texture.Height];
            int nTex = 0; //position in texture array
            int nImage = 0; //position in 8bit image array

            // for each line
            for (int y = 0; y < texture.Height; y++)
            {
                // for each pixel
                for (int x = 0; x < texture.Width; x += 1)
                {
                    byte r = texData[nTex + 0];
                    byte g = texData[nTex + 1];
                    byte b = texData[nTex + 2];
                    // byte a = texData[nTex + 3];

                    int avg = r + g + b;
                    avg /= 3;
                    texData8Bit[nImage] = (byte)avg;
                    nImage += 1;
                    nTex += 4;
                }
                nImage += offset;
            }

            Bitmap bitmap = new Bitmap(texture.Width, texture.Height, PixelFormat.Format8bppIndexed);

            BitmapData bmpData = bitmap.LockBits(
                           new Rectangle(0, 0, texture.Width, texture.Height),
                           ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

            // Get the address of the first line. 
            IntPtr safePtr = bmpData.Scan0;
            Marshal.Copy(texData8Bit, 0, safePtr, texData8Bit.Length);

            // unlock image
            bitmap.UnlockBits(bmpData);
            // Set color palette index to gray
            ColorPalette.SetColorPaletteToGray(bitmap);

            return bitmap;
        }

        /// <summary>
        /// Converts Texture2D to 24 bit Bitmap.
        /// </summary>
        /// <param name="texture">
        /// The texture Object, which will be converted.</param>
        /// <returns>Result Bitmap.</returns>
        public static Bitmap TextureTo24Bit(Texture2D texture)
        {
            byte[] texData = new byte[4 * texture.Width * texture.Height];
            texture.GetData(texData);
            // offset in rgb or 8bit images //wrong: int offset = 4 - (3 * texture.Width) % 4;
            int offset = (3 * texture.Width) % 4;
            if (offset != 0) 
                offset = 4 - offset;
            byte[] texDataRGB = 
                new byte[(3 * texture.Width + offset) * texture.Height];
            int nTex = 0; //position in texture array
            int nRgb = 0; //position in rgb array

            // for each line
            for (int y = 0; y < texture.Height; y++)
            {
                // for each pixel
                for (int x = 0; x < texture.Width; x += 1)
                {                    
                    byte r = texData[nTex + 0];
                    byte g = texData[nTex + 1];
                    byte b = texData[nTex + 2];
                    // byte a = texData[nTex + 3];

                    texDataRGB[nRgb + 2] = r;
                    texDataRGB[nRgb + 1] = g;
                    texDataRGB[nRgb + 0] = b;
                    nRgb += 3;
                    nTex += 4;
                }
                nRgb += offset;
            }

            Bitmap bitmap = new Bitmap(
                texture.Width, texture.Height, PixelFormat.Format24bppRgb);

            BitmapData bmpData = bitmap.LockBits(
                           new Rectangle(0, 0, texture.Width, texture.Height),
                           ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

            // Get the address of the first line. 
            IntPtr safePtr = bmpData.Scan0;
            Marshal.Copy(texDataRGB, 0, safePtr, texDataRGB.Length);

            // unlock image
            bitmap.UnlockBits(bmpData);
            return bitmap;
        }
    }
}
